#pragma once

#include <vector>
#include "llvm/Module.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/Instruction.h"
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Instructions.h"
#include <algorithm>
#include <sys/types.h>
#include <sys/mman.h>

#include "Instrumenter.h"
#include "Utils.h"
#include "Sampler.h"
#include "MemoryProfiler.h"

//typedef Sampler<MemoryProfiler, 256> MySampler;

typedef Instrumenter<LoadInst, MemoryProfiler, void*> MemoryBase;

struct MemoryInstrumenter : public MemoryBase
{
	MemoryInstrumenter(Module *M, ExecutionEngine *EE) : MemoryBase(M, EE) { }
	const Type* getArgType() { return Type::getInt8PtrTy(C); }

	Value* InstrumentThis(LoadInst *Inst) {
		return new BitCastInst(Inst->getOperand(0), Type::getInt8PtrTy(C), "", Inst);
	}
};

typedef Instrumenter<LoadInst, TerminatingMemoryProfiler, void*> TerminatingMemoryBase;

struct TerminatingMemoryInstrumenter : public TerminatingMemoryBase
{
	TerminatingMemoryInstrumenter(Module *M, ExecutionEngine *EE) : TerminatingMemoryBase(M, EE) { }
	const Type* getArgType() { return Type::getInt8PtrTy(C); }

	Value* InstrumentThis(LoadInst *Inst) {
		return new BitCastInst(Inst->getOperand(0), Type::getInt8PtrTy(C), "", Inst);
	}
};
